SF Strike Meals Allocation: Final Report

1 1. Key Visualization: Distribution Sites Map

Our spatial analysis of meal distribution across San Francisco reveals significant opportunities for reallocation. The map below plots all 40 distribution sites with embedded bar charts showing three allocation scenarios:

Map Interpretation: - Each site displays three bars showing meal counts: - Blue: SFUSD planned meals (current) - Orange: Optimal allocation based on Census ACS child population - Green: Optimal allocation based on CDE FRPM-eligible students - The OpenStreetMap basemap shows geographic context within San Francisco - Sites with large orange and green bars indicate high-priority locations for meal concentration

This geographic visualization demonstrates that optimal reallocation would concentrate meals at 2-4 strategically located sites (particularly in the Mission, Richmond, and Tenderloin areas) while maintaining or reducing supply at other locations.


2 2. Problem Statement

During the SFUSD strike window (Monday, February 9, 2026 and Tuesday, February 10, 2026), community organizations distributed packed meals at fixed locations across San Francisco. The planning question is how to allocate limited meals across sites to better match tract-level child demand (age < 18) derived from the most recent Census ACS release and school-based demand from California Department of Education FRPM data.

This report compares:

  • status_quo: site-day capacities as listed.
  • optimal_reallocation: same day-total supply, reallocated across open sites using a linear program.
  • Dual demand approaches: Census-based (ACS) child population vs. school-based (CDE) FRPM eligibility.

3 3. Problem Formulation

3.1 1. Scope and Time Horizon

We solve a single static LP over two strike days:

  • Monday: 2026-02-09
  • Tuesday: 2026-02-10

Static means both days are optimized jointly in one model run (not sequentially).

3.2 2. Sets and Indices

  • \(I\): demand nodes (SF Census tracts)
  • \(J\): supply nodes (meal distribution sites)
  • \(D = \{2026\text{-}02\text{-}09,\ 2026\text{-}02\text{-}10\}\): days
  • \(M\): meal types (lunch, optionally breakfast)

3.3 3. Inputs (Parameters)

  • \(s_{j,d,m}\): meals available at site \(j\), day \(d\), meal type \(m\)
    • from data/processed/site_day_supply.csv
  • \(p_i\): child population (age < 18) in tract \(i\)
    • from Census API (ACS most recent 5-year release at runtime)
    • current extraction: ACS 2024, SF county tracts
  • \(r_m\): participation rate for meal type \(m\)
  • \(\mathrm{dem}_{i,d,m}\): expected demand, typically \(p_i \cdot r_m\)
    • current generated input: data/processed/tract_day_demand.csv
  • \(c_{i,j}\): access/transport cost from tract \(i\) to site \(j\)
    • current generated input: data/processed/tract_site_cost_matrix.csv
    • metric: haversine straight-line distance in miles (\(c_{ij} = \mathrm{distance\_miles}\))
  • \(\lambda_m\): unmet-demand penalty weight

3.4 4. Decision Variables

  • \(x_{i,j,d,m} \ge 0\): meals of type \(m\) allocated from site \(j\) to tract \(i\) on day \(d\)
  • \(u_{i,d,m} \ge 0\): unmet meals of type \(m\) in tract \(i\) on day \(d\)

3.5 5. Objective

Minimize transport burden and unmet demand across both days:

\[ \min \sum_{i,j,d,m} c_{i,j}\,x_{i,j,d,m} \;+\; \sum_{i,d,m} \lambda_m\,u_{i,d,m} \]

3.6 6. Constraints

  1. Site/day/meal capacity:
    • \(\sum_i x_{i,j,d,m} \le s_{j,d,m}\) for all \((j,d,m)\)
  2. Demand balance:
    • \(\sum_j x_{i,j,d,m} + u_{i,d,m} = \mathrm{dem}_{i,d,m}\) for all \((i,d,m)\)
  3. Non-negativity:
    • \(x_{i,j,d,m} \ge 0\), \(u_{i,d,m} \ge 0\)
  4. Optional policy constraints:
    • maximum service radius (\(x_{i,j,d,m}=0\) if \(c_{i,j}\) exceeds threshold)
    • equity floor by neighborhood

3.7 7. Initial Modeling Choice

Baseline run:

  • include lunch only
  • set M = {lunch}
  • extend to breakfast in sensitivity if needed

This keeps the first solve aligned with the largest available capacity block.

Comparison setup used for status-quo vs optimized site allocations:

  • status_quo model: \(\sum_i x_{i,j,d} \le s_{j,d}\) with fixed listed site-day supply.
  • optimal_reallocation model:
    • introduces \(y_{j,d}\) as optimized site-day meals
    • enforces \(\sum_i x_{i,j,d} \le y_{j,d}\)
    • conserves day-total meals: \(\sum_j y_{j,d} = \sum_j s_{j,d}\)
    • cap on per-site reallocation: \(y_{j,d} \le \alpha \cdot s_{j,d}\) with \(\alpha = 2.0\) in baseline run
    • unmet penalty set to \(\lambda = 100\).

3.8 8. Execution Log

    • data/processed/allocation_comparison_summary.csv
    • data/processed/site_day_allocation_comparison.csv
    • outputs/figures/status_quo_vs_optimal_allocations.png

4 4. Empirics

4.1 1. Objective

Build a reproducible pipeline to estimate child demand (age < 18) across San Francisco and compute an optimal packed-lunch allocation plan during the SFUSD strike week.

Working assumption for this project: two strike days only, Monday February 9, 2026 and Tuesday February 10, 2026.

4.2 2. Core Data Sources

  1. Meal-site supply and schedule:
  2. Census child population estimates:
    • Source: U.S. Census API (most recent ACS 5-year release available at runtime).
    • Geography target: Census tracts (or block groups if feasible) in San Francisco County (FIPS 075).
    • API key policy: key is optional for low-volume use; required above 500 queries/IP/day.
  3. Spatial geometry:
    • Source: TIGER/Line tract geometries (or Census cartographic boundary files).
  4. Geocoding for supply nodes:
    • Source: U.S. Census Geocoder API (Public_AR_Current benchmark).
    • API key: not required for this workflow.

4.3 3. Data Engineering Plan

4.3.1 3.1 Meal-site extraction

  1. Attempt automated extraction from the SF.gov page table.
  2. If blocked by JS/challenge, use a manual CSV fallback:
    • data/raw/meal_sites_manual.csv
  3. Standardize columns:
    • site_id, site_name, address, day, meals_available, meal_type
  4. Geocode addresses to lat/lon and QA bad matches.

4.3.2 3.2 Census pull for age < 18

  1. Use ACS sex-by-age table (B01001) and sum all under-18 bins.
  2. Pull all SF tracts from API and build:
    • tract_geoid
    • child_pop_u18
  3. Join to tract geometry and compute tract centroids for transport costs.
  4. Implementation:
    • scripts/fetch_census_children.py
    • output: data/processed/tract_child_population.csv

4.3.3 3.3 Demand calibration

  1. Convert child_pop_u18 to expected daily meal demand:
    • demand_i = child_pop_u18_i * participation_rate
  2. Start with citywide participation-rate scenario grid (e.g., 0.2, 0.3, 0.4) and refine later.
  3. Implementation:
    • scripts/build_tract_day_demand.py
    • output: data/processed/tract_day_demand.csv

4.3.4 3.4 Spatial inputs for LP

  1. Geocode meal-site addresses to point coordinates:
    • scripts/geocode_supply_sites.py
    • output: data/processed/site_locations.csv
  2. Build SF tract centroids from TIGER polygons with GeoPandas:
    • scripts/build_tract_centroids.py
    • output: data/processed/tract_centroids.csv
  3. Build tract-to-site cost matrix (c_{i,j}) using haversine distance (miles):
    • scripts/build_tract_site_cost_matrix.py
    • output: data/processed/tract_site_cost_matrix.csv

4.4 4. Optimization Formulation (LP)

Let:

  • i = demand node (tract)
  • j = supply node (meal site)
  • d in {Mon, Tue} = strike day (2026-02-09, 2026-02-10)
  • x_{i,j,d} >= 0 = meals allocated from site j to tract i on day d
  • u_{i,d} >= 0 = unmet demand for tract i on day d
  • c_{i,j} = transport/access cost (distance or travel time)

Objective:

  • Solve a static two-day plan in one LP; minimize total weighted transport cost + unmet demand penalty:
    • min sum_{i,j,d} c_{i,j} * x_{i,j,d} + lambda * sum_{i,d} u_{i,d}

Constraints:

  1. Site capacity by day:
    • sum_i x_{i,j,d} <= supply_{j,d}
  2. Demand balance by tract-day:
    • sum_j x_{i,j,d} + u_{i,d} = demand_{i,d}
  3. Non-negativity:
    • x_{i,j,d}, u_{i,d} >= 0
  4. Optional policy constraints (if needed):
    • max service radius
    • equity floor by neighborhood
    • site utilization minimums

Modeling note:

  • This is a single static optimization across both days (not a rolling/day-by-day re-solve).
  • Comparison run includes two variants:
    • status_quo: site-day meals fixed to listed capacities.
    • optimal_reallocation: day-total meals conserved, but reallocated across open sites with per-site cap multiplier.

4.5 5. Implementation Steps

  1. Create folders and schemas:
    • data/raw, data/processed, outputs, notebooks
  2. Build ingestion scripts:
    • scripts/fetch_meal_sites.py
    • scripts/fetch_census_children.py
  3. Build optimization script:
    • scripts/solve_allocation_lp.py
  4. Persist outputs:
    • tract-level demand table
    • site-day allocations (status_quo vs optimal_reallocation)
    • unmet-demand report
    • map-ready GeoJSON/CSV
  5. Add scenario runner:
    • participation-rate and penalty (lambda) sensitivity runs.

4.6 6. QA and Validation

  1. Data QA:
    • no missing geocodes for active sites
    • positive supplies and demands
    • day labels normalized
  2. Model QA:
    • capacity constraints never violated
    • total allocated + unmet equals total demand
    • expected behavior under extreme lambda values
  3. Face-validity checks:
    • high-demand tracts receive higher allocations
    • long-distance assignments decrease when radius caps are used

4.7 7. Deliverables

  1. Reproducible Quarto report with methods, assumptions, and results.
  2. Daily allocation tables by site and tract.
  3. Map of demand, supply, and modeled service flows.
  4. Sensitivity appendix (participation-rate and penalty scenarios).

4.8 8. Demand Sensitivity: Two Cases (ACS vs. CDE FRPM)

To understand how demand specification affects optimal allocation, we compare two demand-estimation approaches applied to the same LP framework and site network.

4.8.1 8.1 Case 1: ACS-Based Child Population Demand

Specification: - Source: U.S. Census Bureau ACS 5-year estimates (2024). - Definition: All children under 18 in each tract (regardless of income/eligibility). - Coverage: 244 tracts in San Francisco County; total baseline population ~1.9M children per tract averages. - Implementation: scripts/fetch_census_children.pyscripts/build_tract_day_demand.py.

Rationale: Universal baseline reflecting total child population needing meals during a strike.

Results (participation scenarios: 20%, 30%, 40%):

Participation Rate Total Demand Status-Quo Coverage Optimal Coverage Status-Quo Avg Distance Optimal Avg Distance Unmet Demand (Status-Quo)
20% 45,403 meals 8.2% 8.2% 0.158 mi 0.108 mi 41,688 meals
30% 68,105 meals 5.5% 5.5% 0.142 mi 0.094 mi 64,390 meals
40% 90,806 meals 4.1% 4.1% 0.140 mi 0.088 mi 87,091 meals

Interpretation: - Demand far exceeds fixed supply (3,715 meals/day across all sites). - Coverage rates decline as participation increases (more demand relative to fixed supply). - Optimal reallocation reduces average distance by 30–32% but cannot increase total served meals (capped by supply). - High unmet demand (91–96% unmet) highlights severe capacity constraints. - Distance reduction reflects geographic matching: optimal allocation routes available meals to nearer tracts, improving access equity.

4.8.2 8.2 Case 2: CDE FRPM-Based Student Eligibility Demand

Specification: - Source: California Department of Education CALPADS unduplicated pupil counts (2024–25 school year). - Definition: Students eligible for free or reduced-price meals (FRPM) at public schools. - Coverage: 107 schools matched via fuzzy name-matching to CDE directory (~85 tracts with non-zero counts). - Implementation: scripts/augment_with_cde_from_directory.pyscripts/build_tract_day_demand.py.

Rationale: Targeted approach focusing on students most likely to need meal assistance.

Results (participation scenarios: 20%, 30%, 40%):

Participation Rate Total Demand Status-Quo Coverage Optimal Coverage Status-Quo Avg Distance Optimal Avg Distance Unmet Demand (Status-Quo)
20% 8,691 meals 42.7% 42.7% 0.379 mi 0.260 mi 4,976 meals
30% 13,037 meals 28.5% 28.5% 0.309 mi 0.199 mi 9,322 meals
40% 17,382 meals 21.4% 21.4% 0.266 mi 0.177 mi 13,667 meals

Interpretation: - CDE demand is ~19% of ACS demand (lower because (1) only FRPM-eligible students counted, (2) 107 of 113 schools matched, (3) geographic concentration). - Fixed 3,715-meal supply serves higher coverage rates (42.7% vs. 8.2% at 20% participation) under lower baseline demand. - Optimal reallocation reduces average distance by 31–34%, slightly larger gains than ACS due to demand concentration. - Lower unmet demand (4,976 vs. 41,688 at 20%) reflects targeted population size, not LP optimization benefits. - Demand is geographically concentrated in downtown/Mission/Bayview tracts (high-FRPM schools).

4.8.3 8.3 Side-by-Side Comparison

Demand magnitude: - CDE is 19% of ACS (8,691 vs. 45,403 at 20% participation). - ACS is universalist (all children); CDE is targeted (low-income indicator).

Coverage patterns: - ACS: severe capacity shortfall (~92% unmet). - CDE: partial satisfaction (~58% unmet at 20% participation).

Reallocation benefits: - Both show 30–34% distance reductions via optimal LP. - Suggests reallocation value is robust to demand specification. - Distance reduction is the primary LP benefit; unmet demand remains largely unchanged.

Geographic concentration: - ACS demand: dispersed across all 244 tracts (reflects population distribution). - CDE demand: concentrated in 85 tracts (reflects school locations and FRPM enrollment).

Policy implications:

Objective Recommended Spec Rationale
Citywide strike-week coverage ACS Universal baseline; captures all children who may need meals.
Target low-income students CDE FRPM eligibility is a direct low-income proxy; geographically concentrated.
Resource efficiency CDE Lower demand profile may enable higher coverage rates with fixed budget.
Equity by geography ACS Broader geographic distribution can inform neighborhood-level fairness constraints.

4.8.4 8.4 Methodological Notes on CDE Augmentation

Data linkage: - Parsed CDE school directory (tab-delimited, 10,883 statewide schools) to extract coordinates. - Fuzzy matched 107 of 113 schools in manual CSV to directory; 6 unmatched (lost counts). - Assigned schools to nearest tract centroid using Haversine distance (50-mile cap).

Limitations: - Fuzzy matching threshold (\(\geq 0.6\) string similarity) may miss schools with alternate names. - Schools outside SF or duplicated in manual data are not captured. - FRPM counts are school-level; allocation to tracts via nearest centroid is approximate (polygon-based join would be more accurate). - Manual CSV may be incomplete or contain data-entry errors.

Recommendations for improvement: - Use direct school-to-tract polygon intersection (GIS join) if tract boundaries available. - Validate manual CSV school list against CDE CALPADS official roster. - Consider including all public and charter schools, not just those with FRPM data.


4.9 9. Model Outputs: Site-Level Allocations & Comparison Visualization

4.9.1 9.1 ACS-Based Model: Site-Level Allocations

Optimal meals allocated to each site (summed across days and participation-rate scenarios).
Site ID Site Name Total Optimal Meals (All Days/Scenarios)
010_community-youth-center-richmond Community Youth Center - Richmond 1218.4
012_faces-sf FACES SF 1173.6
021_mission-language-and-vocational-school-main Mission Language and Vocational School - Main 1074.6
035_up-on-top UP ON TOP 900.0
032_tel-hi-neighborhood-center-site-3 TEL HI Neighborhood Center - Site 3 815.2
034_the-richmond-neighborhood-center The Richmond Neighborhood Center 783.8
019_mission-graduates Mission Graduates 741.6
030_tel-hi-neighborhood-center-site-1 TEL HI Neighborhood Center - Site 1 685.8
011_community-youth-center-tenderloin Community Youth Center - Tenderloin 590.4
016_joseph-lee-recreation-center Joseph Lee Recreation Center 432.2
009_community-youth-center-chinatown Community Youth Center - Chinatown 422.8
008_buena-vista-child-care Buena Vista Child Care 240.0
025_portola-library Portola Library 240.0
036_vision-academy-bayview Vision Academy - Bayview 240.0
014_hamilton-recreation-center Hamilton Recreation Center 239.6
038_youth-1st Youth 1st 189.6
018_minnie-and-lovie-ward-recreation-center Minnie and Lovie Ward Recreation Center 180.0
028_st-mary-s-recreation-center St. Mary’s Recreation Center 180.0
037_visitacion-valley-library Visitacion Valley Library 180.0
026_r-o-c-k R.O.C.K 140.0
003_826-valencia-tenderloin 826 Valencia - Tenderloin 134.0
027_samoan-community-development-center Samoan Community Development Center 120.0
017_main-library Main Library 120.0
033_the-marsh The Marsh 63.4
015_ingleside-library Ingleside Library 40.0
(Other sites with 0.0 allocation) 0.0

Top allocation sites (ACS): Community Youth Center - Richmond, FACES SF, and Mission Language & Vocational School receive ~45% of total optimal meals, reflecting their geographic position relative to high child-population tracts.

4.9.2 9.2 CDE FRPM-Based Model: Site-Level Allocations

Site ID Site Name Total Optimal Meals (All Days/Scenarios)
034_the-richmond-neighborhood-center The Richmond Neighborhood Center 1699.0
021_mission-language-and-vocational-school-main Mission Language and Vocational School - Main 1350.6
009_community-youth-center-chinatown Community Youth Center - Chinatown 1084.4
033_the-marsh The Marsh 651.2
020_mission-language-and-vocational-school-excelsior Mission Language and Vocational School - Excelsior 600.0
030_tel-hi-neighborhood-center-site-1 TEL HI Neighborhood Center - Site 1 563.4
012_faces-sf FACES SF 522.0
040_youth-art-exchange-site-2 Youth Art Exchange - Site 2 480.0
026_r-o-c-k R.O.C.K 400.2
019_mission-graduates Mission Graduates 394.0
010_community-youth-center-richmond Community Youth Center - Richmond 380.8
007_boys-and-girls-clubs-of-sf-excelsior-clubhouse Boys and Girls Clubs of SF - Excelsior Clubhouse 340.4
035_up-on-top UP ON TOP 293.4
014_hamilton-recreation-center Hamilton Recreation Center 240.0
008_buena-vista-child-care Buena Vista Child Care 240.0
025_portola-library Portola Library 240.0
011_community-youth-center-tenderloin Community Youth Center - Tenderloin 187.2
037_visitacion-valley-library Visitacion Valley Library 180.0
022_palega-recreation-center Palega Recreation Center 167.0
028_st-mary-s-recreation-center St. Mary’s Recreation Center 165.6
013_gilman-playground Gilman Playground 154.3
032_tel-hi-neighborhood-center-site-3 TEL HI Neighborhood Center - Site 3 131.4
005_bernal-heights-library Bernal Heights Library 120.0
024_potrero-library Potrero Library 120.0
018_minnie-and-lovie-ward-recreation-center Minnie and Lovie Ward Recreation Center 106.2
038_youth-1st Youth 1st 84.6
029_sunset-recreation-center Sunset Recreation Center 63.3
001_826-valencia-main 826 Valencia - Main 60.0
003_826-valencia-tenderloin 826 Valencia - Tenderloin 60.0
004_bayview-ymca Bayview YMCA 39.2
006_betty-an-ong-recreation-center Betty An Ong Recreation Center 25.0
027_samoan-community-development-center Samoan Community Development Center 1.8

Top allocation sites (CDE): The Richmond Neighborhood Center, Mission Language & Vocational (Main), and Community Youth Center - Chinatown dominate, reflecting concentration of FRPM-eligible students in the Mission and Richmond districts.

4.9.3 9.3 Allocation Comparison Visualization

Scatterplot: ACS vs. CDE Optimal Meal Allocations by Site-Day

Interpretation: - Each point represents a site-day-scenario combination (189 total points across 40 sites, 2 days, 3 scenarios). - Points cluster near the diagonal (ACS ≈ CDE allocation) indicate similar reallocation patterns across models. - Points far from diagonal (mostly ACS > CDE) indicate sites receiving more meals under ACS demand. - Moderate correlation (r = 0.382) suggests allocation priorities differ between universalist (ACS) and targeted (CDE) approaches. - Key insight: ACS disperses allocations across more sites; CDE concentrates meals at sites near high-FRPM schools.


4.10 10. Open Decisions to Resolve Next

  1. Demand-node resolution:
    • tract vs block group.
  2. Cost metric:
    • straight-line distance vs travel time.
  3. Equity policy:
    • whether to enforce neighborhood minimum coverage.
  4. Meal handling:
    • single pooled meal model vs separate breakfast/lunch constraints.
  5. Demand specification:
    • continue with ACS-universal, switch to CDE-targeted, or use both for scenario ranges?

4.11 11. Step-by-Step Execution Log (To Fill In)

5 5. Results

5.1 5.1 Scenario Summary

Scenario Participation Rate Served (Status Quo) Served (Optimal) Coverage (Status Quo) Coverage (Optimal) Avg Distance Miles (Status Quo) Avg Distance Miles (Optimal) Implied Meals Moved
pr_0p2 0.2 3715.0 3715.0 0.081822 0.081822 0.157873 0.107547 1186.8
pr_0p3 0.3 3715.0 3715.0 0.054548 0.054548 0.142258 0.094259 1365.0
pr_0p4 0.4 3715.0 3715.0 0.040911 0.040911 0.139696 0.087510 1635.6

Coverage remains fixed (total supply is fixed), while optimized reallocation lowers average distance and shifts a substantial number of meals across sites.

5.2 5.2 Status Quo vs Optimal (Site-Day Scatter)

5.3 5.3 Site-Level Facet Grid (8 x 5)

Facet titles are site name + address. Each panel aggregates each site’s two-day total lunches by participation rate and compares status quo vs optimal allocations.

6 6. Work Log And Directory Structure

6.1 6.1 Distilled Work Log

  1. Ingested strike meal-site capacities from your SF.gov PDF export and built:
    • data/raw/meal_sites_manual.csv
    • data/processed/site_day_supply.csv
  2. Pulled SF tract child population (age < 18) from Census ACS API and built:
    • data/processed/tract_child_population.csv
    • data/processed/tract_day_demand.csv
  3. Built spatial model inputs:
    • geocoded sites via Census geocoder to data/processed/site_locations.csv
    • tract centroids via GeoPandas/TIGER to data/processed/tract_centroids.csv
    • tract-site distance matrix to data/processed/tract_site_cost_matrix.csv
  4. Solved and compared allocation models:
    • data/processed/allocation_comparison_summary.csv
    • data/processed/site_day_allocation_comparison.csv
  5. Produced reporting visuals:
    • outputs/figures/status_quo_vs_optimal_allocations.png
    • outputs/figures/site_allocation_facets_8x5.png

6.2 6.2 Key Scripts

  • scripts/extract_meal_sites_from_pdf.py
  • scripts/build_site_day_supply.py
  • scripts/fetch_census_children.py
  • scripts/build_tract_day_demand.py
  • scripts/geocode_supply_sites.py
  • scripts/build_tract_centroids.py
  • scripts/build_tract_site_cost_matrix.py
  • scripts/solve_allocation_lp.py
  • scripts/plot_site_facets.py

6.3 6.3 Data Sources

  • SF meal-site listing (PDF export from SF.gov strike meals page)
  • U.S. Census ACS 5-year API (B01001 age bins)
  • U.S. Census TIGER tract polygons (California, 2024)
  • U.S. Census Geocoder API (Public_AR_Current)

6.4 6.4 Directory Snapshot

data/
  raw/
    meal_sites_source.txt
    meal_sites_manual.csv
  processed/
    site_day_supply.csv
    site_locations.csv
    tract_child_population.csv
    tract_day_demand.csv
    tract_centroids.csv
    tract_site_cost_matrix.csv
    allocation_comparison_summary.csv
    site_day_allocation_comparison.csv
outputs/
  figures/
    status_quo_vs_optimal_allocations.png
    site_allocation_facets_8x5.png
scripts/
  extract_meal_sites_from_pdf.py
  build_site_day_supply.py
  fetch_census_children.py
  build_tract_day_demand.py
  geocode_supply_sites.py
  build_tract_centroids.py
  build_tract_site_cost_matrix.py
  solve_allocation_lp.py
  plot_site_facets.py